package cn.yunyichina.provider.pay.wechat.service.impl;

import cn.yunyichina.provider.framework.dubbo.service.PayService;
import cn.yunyichina.provider.framework.qiniu.QiniuService;
import cn.yunyichina.provider.framework.utils.CSVUtils;
import cn.yunyichina.provider.iface.entity.common.ResCommon;
import cn.yunyichina.provider.iface.entity.common.Response;
import cn.yunyichina.provider.iface.entity.common.ResponseObject;
import cn.yunyichina.provider.iface.entity.pay.PaymentSettingResponse;
import cn.yunyichina.provider.iface.entity.pay.WechatMedicalBillDownloadRequest;
import cn.yunyichina.provider.iface.entity.pay.WechatMedicalBillDownloadResponse;
import cn.yunyichina.provider.pay.wechat.common.XMLUtil;
import cn.yunyichina.provider.pay.wechat.config.Config;
import cn.yunyichina.provider.pay.wechat.config.Wechat;
import cn.yunyichina.provider.pay.wechat.entity.common.WechatAccessTokenResponse;
import cn.yunyichina.provider.pay.wechat.service.WechatAuthService;
import cn.yunyichina.provider.pay.wechat.service.WechatDownloadService;
import cn.yunyichina.provider.pay.wechat.service.WechatPayService;
import cn.yunyichina.utils.commons.HttpUtil;
import cn.yunyichina.utils.commons.RandomUtil;
import cn.yunyichina.utils.convert.JsonUtils;
import cn.yunyichina.utils.convert.XmlUtils;
import cn.yunyichina.utils.security.SignUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

/**
 * 微信对账单下载
 * Created by JoeZ on 2016/10/18.
 */
@Service
public class WechatDownloadServiceImpl implements WechatDownloadService {

//    private final String BILL_TYPE = "ALL";
//    private final String URL = "https://api.mch.weixin.qq.com/pay/downloadbill";

    @Resource
    private Properties yaml;

    private String resultCode = "";
    private String resultMessage = "";

    @Autowired
    private WechatPayService wechatPayService;

    @Autowired
    private WechatAuthService wechatAuthService;

    private static final Logger logger = LoggerFactory.getLogger(WechatDownloadServiceImpl.class);


    /**
     * 获取本地对账文件路径
     * @interfaceName: yyt.wechatpay.wechat.download.bill.file.get
     * @return
     */
    @Override
    public Response getWechatDownloadBillFile(String json) {
        logger.info("WechatDownloadServiceImpl.getWechatDownloadBillFile json-->" + JsonUtils.toJsonString(json));
        String savePath = yaml.getProperty(Wechat.WECHAT_PAY_CHECK_ACCOUNT_SAVE_FILE_PATH);
        String url = yaml.getProperty(Wechat.WECHAT_PAY_BILL_DOWNLOAD_URL);

        Response response = new Response();

        Map<String , String> map = JSON.parseObject(json, Map.class);
        String date = map.get("date");
        String appId = map.get("app_id");
        String payKey = map.get("pay_key");
        String orgName = map.get("org_name");
        String mchId = map.get("mch_id");

        if(date.contains("-")){
            date = date.replace("-", "");
        }

        try {

            Map<String,String> resMap = new HashMap<String,String>();

            //获取微信自费订单
            String xml = getBillDataFileParameters(date, appId, mchId, payKey , Wechat.WECHAT_PAY_CHECK_ACCOUNT_TYPE);
            List<List<Object>> dataList = null;
            try {
                logger.info("WechatDownloadServiceImpl.getWechatDownloadBillFile "+ orgName +" 获取微信自费账单开始-->" + appId);
                dataList = weChatBillPost(url, xml);
            } catch (Exception e) {
                logger.error("[WechatServiceImpl.weChatBillPost 微信自费账单获取异常]" , e);
                response.setResultCodeAndMessage(resultCode , resultMessage);
                return response;
            }
            if("success".equals(resultCode)){
                if(dataList != null){
                    Map<String, String> uploadSave = qiniuUploadSave(orgName, date, appId, savePath, dataList, false);
                    resMap.put("fileName" , uploadSave.get("fileName"));
                    logger.info(orgName + "_" + appId + " 本地微信自费文件获取成功!");
                    response.setResultCodeAndMessageAndResult("0" , "本地微信自费文件获取成功!", JSONObject.toJSONString(resMap));
                }
            }else{
                response.setResultCodeAndMessage(resultCode,resultMessage);
            }


            //获取微信医保订单
            WechatMedicalBillDownloadRequest request = new WechatMedicalBillDownloadRequest();
            request.setAppid(appId);
            request.setBillDate(date);
            try {
                logger.info("WechatDownloadServiceImpl.getWechatDownloadBillFile "+ orgName +" 获取微信医保账单开始-->" + appId);
                Response insResponse = getWechatDownloadInsuranceBillFile(JSON.toJSONString(request));
                if("0".equals(insResponse.getResultCode())){
                    List<List<Object>> list = JSONObject.parseObject(insResponse.getResult(), List.class);
                    Map<String, String> uploadSave = qiniuUploadSave(orgName, date, appId, savePath, list, true);
                    resMap.put("insFileName" , uploadSave.get("fileName"));
                    logger.info(orgName + "_" + appId + " 本地微信医保文件获取成功!");
                    response.setResultCodeAndMessageAndResult("0" , "本地微信医保文件获取成功!", JSONObject.toJSONString(resMap));
                }else{
                    logger.info(orgName + "_" + mchId + "_微信医保账单微信不存在.");
                }
            } catch (Exception e) {
                logger.error("[WechatServiceImpl.getWechatDownloadInsuranceBillFile] 微信医保账单获取异常" , e);
            }

        } catch (Exception e) {
            logger.error("[WechatServiceImpl.billFileDataProcessing]" , e);
        }

        return response;
    }




    /**
     * 获取微信医保对账单
     * @interfaceName: yyt.wechatpay.wechat.download.insurance.bill.file.get
     * @return
     */
    public Response getWechatDownloadInsuranceBillFile (String json) throws Exception{

        Response response = new Response();
        WechatMedicalBillDownloadRequest request = JSON.parseObject(json, WechatMedicalBillDownloadRequest.class);

        //根据医院appId查询该支付参数
        ResCommon<PaymentSettingResponse> settingResponseResCommon = PayService.getPayClient().queryPaymentSettingByAppId(request.getAppid());
        String payAppId = settingResponseResCommon.getResult().getPayAppId();
        String parentId = settingResponseResCommon.getResult().getParentId();
        String mchId = settingResponseResCommon.getResult().getMerchantAccount();

        if(StringUtils.isBlank(parentId)){
            logger.info("该appId：" + request.getAppid() + ",不存在parentId");
            response.setResultCodeAndMessage("12010" , "该appId：" + request.getAppid() + ",不存在parentId");
            return response;
        }

        //查询父配置参数
        ResCommon<PaymentSettingResponse> paymentSetting = PayService.getPayClient().getPaymentSettingById(parentId);

        String parentPayAppId = paymentSetting.getResult().getPayAppId();
        String parentMchId = paymentSetting.getResult().getMerchantAccount();
        String secretKey = paymentSetting.getResult().getSecretKey();
        String medicarePayKey = paymentSetting.getResult().getMedicarePayKey();

        ResponseObject o = wechatAuthService.getWechatAuthMedicalAccessToken("{\"grant_type\":\"client_credential\",\"appid\":\""+ request.getAppid() +"\",\"agentsecret\":\""+ secretKey +"\",\"agentappid\":\""+ parentPayAppId +"\"}");
        String accessToken=((WechatAccessTokenResponse)o.getResultObject()).getAccessToken();

        request.setAppid(parentPayAppId);
        request.setSubAppid(payAppId);
        request.setMchId(parentMchId);
        request.setSubMchId(mchId);
        request.setApiSecret(medicarePayKey);
        request.setAccessToken(accessToken);
        request.setBillType(Wechat.WECHAT_PAY_CHECK_ACCOUNT_TYPE);

        ResCommon<WechatMedicalBillDownloadResponse> resCommon = wechatPayService.downloadWechatMedicalBill(request);

        if("0".equals(resCommon.getResultCode())){

            String[] strings = resCommon.getResult().getResult().split("\n");

            StringBuffer buffer = new StringBuffer();
            List<List<Object>>list = new ArrayList<List<Object>>();

            for (int i = 0; i < strings.length; i++) {
                buffer.append(strings[i]); // 将读到的内容添加到 buffer 中
                buffer.append("\n"); // 添加换行符
                logger.info(strings[i]);
                List<Object> bList = new ArrayList<>();
                String[] split = strings[i].split("\\,");
                for (int j = 0; j < split.length; j++) {
                    bList.add(split[j]);
                }
                list.add(bList);
            }

            response.setResultCodeAndMessageAndResult(Response.SUCCESS_CODE , Response.SUCCESS_MESSAGE , JSON.toJSONString(list));
        }else{
            logger.info(request.getHospitalName()  + request.getBillDate() +" 微信医保对账文件下载失败! message:" + resCommon.getResultMessage());
            response.setResultCodeAndMessage(Response.FAILURE_CODE , request.getHospitalName()  + request.getBillDate() +" 微信医保对账文件下载失败! message:" + resCommon.getResultMessage());
        }

        return response;
    }


    /**
     * 构造七牛上传参数
     * @param orgName
     * @param date
     * @param appId
     * @param savePath 本地存储路径
     * @param dataList 数据集合
     * @param insFlag 医保单标示  true：医保单
     * @return
     * @throws Exception
     */
    public Map<String,String> qiniuUploadSave(String orgName , String date , String appId , String savePath , List<List<Object>> dataList , Boolean insFlag) throws Exception{
        Map<String,String> map = new HashMap<String,String>();
        String fileName = "";
        if(insFlag){
            fileName = orgName + "_wechat_" + date + "_" + appId +"_医保单.csv";
        }else{
            fileName = orgName + "_wechat_" + date + "_" + appId +".csv";
        }
        logger.info(">>> FileName : " + fileName);
        File csvFile = CSVUtils.createCSVFile(null, savePath, fileName, dataList);
        if (csvFile != null) {
            String filePath = csvFile.getCanonicalPath();
            logger.info(">>> OutPutPath : " + filePath);

            //上传到Qiniu服务器
            com.qiniu.http.Response res = QiniuService.upload(filePath, fileName, Config.QINIU_BUCKET_FOR_CHECKACCOUNT);
            if(res.isOK() || res.statusCode == 614){
                map.put("fileName" , fileName);
                map.put("resultCode" , "0");
                map.put("resultMessage" , "本地文件获取成功");
            }else{
                logger.info("check_account_file_qiniu_download_fail!!");
                map.put("resultCode" , "12001");
                map.put("resultMessage" , "check_account_file_qiniu_download_fail!!上传七牛失败");
            }
        }else{
            logger.info("check_account_file_qiniu_createfile_fail!!");
            map.put("resultCode" , "12002");
            map.put("resultMessage" , "check_account_file_qiniu_createfile_fail!! 构造csv文件失败");
        }

        return map;
    }



    /**
     * 获取微信对账单封装请求参数
     *
     * @return
     */
    public String getBillDataFileParameters(String date, String appId, String mchId, String payKey, String billType) {
        String xmlStr = XMLUtil.buildMapXML(buildWechatDownloadbillParameters(date, appId, mchId, payKey , billType));
        return xmlStr;
    }



    /**
     * 请求参数拼装
     *
     * @param date
     * @return
     */
    private Map<String, String> buildWechatDownloadbillParameters(String date, String appId, String mchId, String payKey,String billType) {
        Map<String, String> params = new HashMap<>();
        params.put("appid", appId);
        params.put("mch_id", mchId);
        params.put("nonce_str", RandomUtil.getRandomALLCharToUpperCase(32));
        params.put("bill_date", date);
        params.put("bill_type", billType);
        params.put("sign", getWechatPaySign(params, payKey));
        return params;
    }



    private String getWechatPaySign(Map<String, String> params , String payKey) {
        String[] keys = new String[params.size()];
        params.keySet().toArray(keys);
        Arrays.sort(keys);
        StringBuffer target = new StringBuffer();
        for (String key : keys) {
            String value = params.get(key);
            if (StringUtils.isNotBlank(value)) {
                target.append(key).append("=").append(value).append("&");
            }
        }
        target.append("key=").append(payKey);
        return DigestUtils.md5Hex(target.toString());
    }


    /**
     * 请求获取对账文件数据
     *
     * @param urlStr
     * @return
     */

    public  List<List<Object>> weChatBillPost(String urlStr, String xml) throws Exception{
        BufferedReader br= null;
        HttpURLConnection con=null;
        OutputStreamWriter out=null;
        List<List<Object>> list = null;
        try {
            URL url = new URL(urlStr);
            // URLConnection con = url.openConnection();
            con = (HttpURLConnection) url.openConnection();
            // 发送POST请求必须设置如下两行
            con.setDoOutput(true);  // POST方式
            con.setDoInput(true);
            con.setUseCaches(false);
            con.setRequestMethod("POST");
            // 设置通用的请求属性
            con.setRequestProperty("accept", "*/*");
            con.setRequestProperty("connection", "Keep-Alive");
            con.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

            // 输出流，写数据
            out = new OutputStreamWriter(con
                    .getOutputStream(),"UTF-8");

            // 发送请求参数
            String xmlInfo = xml.trim();
            logger.info("urlStr = " + urlStr);
            logger.info("xmlInfo = " + xmlInfo);
            out.write(new String(xmlInfo.getBytes("UTF-8")));
            // flush输出流的缓冲
            out.flush();
            // out.close();
            //读取服务器的响应内容并显示 定义BufferedReader输入流来读取URL的响应
            br = new BufferedReader(new InputStreamReader(con
                    .getInputStream(),"UTF-8"));
            String line = "";
            StringBuffer buffer = new StringBuffer();

            list = new ArrayList<>();
            while ((line = br.readLine()) != null)
            {
                buffer.append(line); // 将读到的内容添加到 buffer 中
                buffer.append("\n"); // 添加换行符
                logger.info(line);
                List<Object> bList = new ArrayList<>();
                String[] split = line.split("\\,");
                for (int i = 0; i < split.length; i++) {
                    bList.add(split[i]);
                }
                list.add(bList);
            }

            //解析返回xml文件
            String resXml = buffer.toString();
            if(XmlUtils.isXml(resXml)){
                Document document = DocumentHelper.parseText(resXml);
                Element root = document.getRootElement();
                String returnCode = root.element("return_code").getStringValue();
                String returnMsg = root.element("return_msg").getStringValue();

                if("FAIL".equals(returnCode)){
                    resultCode = returnCode;
                    resultMessage = returnMsg;
                    logger.error("获取微信账单失败~：" + returnMsg);
                }

            }else{
                resultCode = "success";
                resultMessage = "成功";
            }

            //con.getOutputStream().close();
        }finally {
            try {
                if(out!=null){
                    out.close();
                }

                if (br != null)
                {
                    br.close();
                    con.disconnect();
                }
            } catch (Exception e2) {
                logger.error("[WechatDownloadServiceImpl.weChatBillPost]",e2);
            }
        }

        return list;

    }

    public static void main(String[] args) throws DocumentException, IOException {
//        String url="https://api.mch.weixin.qq.com/pay/downloadbill";
//        String content="<xml><sign><![CDATA[0765be9464de0fb61a1920ab16030df3]]></sign><mch_id><![CDATA[1427399002]]></mch_id><appid><![CDATA[wx8d06256bd3e86fa8]]></appid><nonce_str><![CDATA[SRJY0G1XOFERJGKCN6237YMMIB5WKYUA]]></nonce_str><bill_type><![CDATA[ALL]]></bill_type><bill_date><![CDATA[20170818]]></bill_date></xml>";
//        WechatDownloadServiceImpl impl=new WechatDownloadServiceImpl();
//        try {
//            impl.weChatBillPost(url,content);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }

        //----------------------------------------------------------------------------------------
//        WechatDownloadServiceImpl impl=new WechatDownloadServiceImpl();
//        String xml = impl.getBillDataFileParameters("20170901", "wxde4cc244f554acfd", "1398840802", "1p2485gvbs8ebcawjo6o3ymrbhez75xn" , Wechat.WECHAT_PAY_CHECK_ACCOUNT_TYPE);
//        List<List<Object>> dataList = null;
//        try {
//            dataList = impl.weChatBillPost("https://api.mch.weixin.qq.com/pay/downloadbill", xml);
//        } catch (Exception e) {
//            logger.error("[WechatServiceImpl.weChatBillPost]" , e);
//        }
//        System.out.println(JSON.toJSONString(dataList));
        //----------------------------------------------------------------------------------------


        WechatAuthServiceImpl authService=new WechatAuthServiceImpl();
        ResponseObject o=authService.getWechatAuthMedicalAccessToken("{\"grant_type\":\"client_credential\",\"appid\":\"wx8d06256bd3e86fa8\",\"agentsecret\":\"df2e4c7c67533f6b443fc2153fa794d7\",\"agentappid\":\"wxde4cc244f554acfd\"}");
        String accessToken=((WechatAccessTokenResponse)o.getResultObject()).getAccessToken();
        System.out.println(accessToken);

        String apiSecret="bb28ce9dfe2bb4037124aaabb2faa1e7";

        Map<String, String> requestMap =new HashMap<>();
        requestMap.put("appid","wxde4cc244f554acfd");
        requestMap.put("sub_appid","wx8d06256bd3e86fa8");
        requestMap.put("mch_id","1398840802");
        requestMap.put("sub_mch_id","1427399002");
        requestMap.put("bill_date","20170901");
        requestMap.put("bill_type","ALL");
        requestMap.put("nonce_str",RandomUtil.getRandomALLChar(32));
        requestMap.put("sign", SignUtil.wechatPaySign(requestMap, apiSecret));

        String xml = XMLUtil.buildMapXML(requestMap);

        String requestUrl = String.format("https://api.weixin.qq.com/payinsurance/getbalancebill?access_token=%s", accessToken);
        System.out.println(requestUrl);
        String result = HttpUtil.post(xml, requestUrl);
        System.out.println(result);

    }

}
